import Cocoa

//var str = "Hello, playground"


//元组
//元组内的值可以是任意类型，而且可以不必是统一类型
//创建元组
var error = (1, "没有权限")  //元组内的值是任意类型
print(error)
//可以像数组一样通过元组的下标获取元组的值
print(error.0)
print(error.1)

//可以像oc中的字典一样.通过键名获取元组的值
var error2 = (errorCode: 1, errorMessasge: "没有权限")
print(error2)
print(error2.errorCode)
print(error2.errorMessasge)

//可以在声明的时候就写上元素的类型(Any用来表示任意类型的)
var error3: (errorCode: Int, errorMessage: Any) = (errorCode: 1, errorMessage: "没有权限")
//可以修改元组的值
error3.errorCode = 2;
error3.errorMessage = 123
print(error3)

//解包用法
let error4 = (1, "没有权限")
let (errorCode, errorMessage) = error4
print("code:\(errorCode),message:\(errorMessage)")

//元组作为返回值
func writeFile(content: String) -> (errorCode: Int, errorMessage: String) {
    return (1, "没有权限")
}
//调用函数
let error5 = writeFile(content: "写入文件.txt")
print("error5:\(error5)")





/**
 Objective-C与Swift语言对于可选nil的不同理解:
 
 Objective-C中的nil:表示缺少一个合法的对象，是指向不存在对象的指针，对结构体、枚举等类型不起作用(会返回NSNotFound)
 
 Swift中的nil:表示任意类型的值缺失，是一个确定的值，要么是该类型的一个值要么什么都没有(即为nil)
 */



//可选项
//非可选型不可以设置为nil,否则会报错
//var str: String = nil
//声明可选String类型的变量,初始值为nil
var str2: String? = nil
//声明可选String类型的变量,初始值为"你好呀"
var str3: String? = "你好呀"


//使用"!强行"解析获取可选类型的值(不建议直接使用)
//需要使用if进行展开
if str3 != nil {
    let count = str3!.count  //使用"!"强行解析
    print(count)
}

//使用可选绑定获取可选类型的值(建议使用)
if let tempStr = str3 {  //如果str3有值获取类型转换成功,则将值赋值给tempStr直接使用
    print("tempStr is \(tempStr)")  //使用tempStr代替str3,切不需要加!强制解析
} else {
    print("str3 is nil")
}

//隐式解析可选类型,使用!(用于申明是肯定有初始值,但后面可能为nil)
var mobileNumber: Int64! = 187734098765  //第一次申明有初始值
var mobileNumber2: Int64! = nil  //这样也不会报错
print("您的电话号码是:\(String(describing: mobileNumber))")  //打印内容是:您的电话号码是:Optional(187734098765)
//还是不建议直接强制解析,因为实际项目中可能中间已经对该值做了改变,若为nil则会运行错误导致APP崩溃

//建议的做法
if let number = mobileNumber {
    print("你的电话号码是:\(number)")  //此时打印:你的电话号码是:187734098765
} else {
    print("你的电话号码为空号")
}

//可选项链,在可选项后面加?还是可选项,如果可选项不为nil,则返回一个可选项结果,否则返回nil
var str4: String? = "abc"
let count2 = str4?.count  //在可选项的后面加?
if count2 != nil {  //使用!展开count2的数据
    print("count2 is \(count2! - 1)")
}


//optional的底层就是一个public的枚举,而且是泛型的类型,他有两个属性,一个是none,也就是nil,一个是some
//可以将之前的?改成optional,效果是一样的
var str5: Optional<String> = "abc"
if let str6 = str5 {
    print("str6 is \(str6)")
}

//因为他是一个泛型(unsafelyUnwrapped),所以展开也可以使用unsafelyUnwrapped去替代!,效果也是一样的
var str7: String? = "abc"
if str7 != nil {
    print("str7 is \(str7.unsafelyUnwrapped)")
}

//合并空值运算符 (a ?? b),如果可选项a有值则展开,没有没有值,值是nil,默认返回b的值
//合并空值运算符实际上是一个三元表达式:(a ?? b )等价于 a != nil ? a! : b
let a: Int? = nil //声明了一个可选Int类型的变量a,默认值是nil
let b = 10
print(a ?? b)  //判断a是否为nil,若有值,则展开a的值,若没有值,则为nil,默认返回b的值,此时返回的是b的值:10

//声明一个求和的函数
//直接拆包,具有危险性
func addTwoNumbers(num1: Int?, num2: Int?) -> Int {
    //直接拆包,具有危险性,不建议这样使用!来直接解析可选项的值
    return num1! + num2!;
}

//以往的写法过于繁琐
func addTwoNumbers1(num1: Int?, num2: Int?) -> Int {
    if num1 != nil {
        if num2 != nil {
            return num1! + num2!
        } else {
           return num1!
        }
    } else {
        if num2 != nil {
            return num2!
        } else {
            return 0
        }
    }
}

func addTwoNumbers2(num1: Int?, num2: Int?) -> Int {
    //使用合并空值运算符一行就搞定,不用写那么多的判断
    return (num1 ?? 0) + (num2 ?? 0)
}

print(addTwoNumbers(num1: 10, num2: 20))











